package geneticprogramming;

import java.util.ArrayList;
import java.util.List;

public class Population extends Thread {
	
	/**
     * size of Population.
     */
	private int PopSize;
	/**
     * height of tree.
     */
    private int hieghtOfTree;
    /**
     * Number of trees.
     */
     private int numberOfTrees;
     /**
      * Population.
      */
     private List<Tree> population = null;
     /**
      * The Generation.
      */
     private int generation = 0;
     /**
      * Start time.
      */
     private long startTime = 0;
     /**
      * Allow the same gene.
      */
     private boolean acceptDuplicates;
	
     private TerminalSet terminalSet = new TerminalSet();
	 private FunctionalSet functionalSet = new FunctionalSet();
	
	/*
	 * Generating population 
	 * Need to add Ramped Half and Half Initialize
	 */
	private List<Tree> populate(final int newNumberOfTrees,
             final int newHeight) throws GeneticProgrammingException {
     this.population = new ArrayList<Tree>();
     for (int y = 0; y < newNumberOfTrees; y++) {
             final Node rootNode = new Node(null, this.getFunctionalSet()
                             .randomOperator(), null, Node.OPERATOR);
             final Tree tree = new Tree(rootNode, this.getTerminalSet(), this
                             .getFunctionalSet());
             rootNode.setTree(tree);
             generateNodes(tree, rootNode, newHeight);

             this.population.add(tree);
     }

     return population;
	}
	
	/**
     * Method for populating a tree with nodes.
     * 
     * @param newTree
     *            - Tree that needs nodes generated
     * @param newParent
     *            - Parent node to attach sibling (leaf) nodes onto.
     * @param howDeepToMakeIt
     *            - The total depth to make the tree.
     * @throws GeneticProgrammingException
     *             - something went wrong
     */
	
	private void generateNodes(final Tree newTree, final Node newParent,
               final int howDeepToMakeIt) throws GeneticProgrammingException {
       if (newParent.getLevel() == howDeepToMakeIt - 1) {
               final Node lOperand = new Node(newParent, getTerminalSet()
                               .randomOperand(), Node.LEFT, Node.OPERAND);
               newTree.addNode(lOperand);
               final Node rOperand = new Node(newParent, getTerminalSet()
                               .randomOperand(), Node.RIGHT, Node.OPERAND);
               newTree.addNode(rOperand);
       } else {
               final Node lOperator = new Node(newParent, getFunctionalSet()
                               .randomOperator(), Node.LEFT, Node.OPERATOR);
               newTree.addNode(lOperator);
               generateNodes(newTree, lOperator, howDeepToMakeIt);
               final Node rOperator = new Node(newParent, getFunctionalSet()
                               .randomOperator(), Node.RIGHT, Node.OPERATOR);
               newTree.addNode(rOperator);
               generateNodes(newTree, rOperator, howDeepToMakeIt);
       }

	}
	
	@Override
    public final void run() {
            try {
                    startTime = System.currentTimeMillis();
                    /*final List<Tree> populationTree =*/ populate(this.getNumberOfTrees(),
                                    this.getHieghtOfTree());
                } catch (GeneticProgrammingException e) {
                    e.printStackTrace();
            }
    }
		
	public final int getPopSize() {
         return this.PopSize;
	}
	
	public final void setValue(final int newPopSize) {
         this.PopSize = newPopSize;
	}
	
	private TerminalSet getTerminalSet() {
        return this.terminalSet;
	}
	
	private FunctionalSet getFunctionalSet() {
        return this.functionalSet;
	}
	
	public final void setNumberOfTrees(final int newNumberOfTrees) {
        this.numberOfTrees = newNumberOfTrees;
	}
	
	private int getNumberOfTrees() {
        return this.numberOfTrees;
	}
	
	public final void setPopulation(final List<Tree> newPopulation) {
        this.population = newPopulation;
	}
	
	public final void setGeneration(final int newGeneration) {
         this.generation = newGeneration;
	}
	
    private int getHieghtOfTree() {
            return this.hieghtOfTree;
    }
	
}
